/*
 * CommunicationCanastos.cpp
 *
 *  Created on: 16/11/2013
 *      Author: gonzalo
 */

#include "CommunicationCanastos.h"
#include "../capa_servicios_distribuidos/QueueLauncher.h"

namespace middleware {

const std::string CommunicationCanastos::AGV_SHMEM_CANASTOS_PATH = "/tmp/canastos";
const char CommunicationCanastos::AGV_SHMEM_CANASTOS_KEY_IZQ = 'i';
const char CommunicationCanastos::AGV_SHMEM_CANASTOS_KEY_DER = 'd';
const char CommunicationCanastos::AGV_SHMEM_CANASTOS_KEY_MED = 'm';

CommunicationCanastos::CommunicationCanastos(char zonaKey)
{
    switch ( zonaKey )
    {
    case AGV_SHMEM_CANASTOS_KEY_IZQ:
        shMemCanastos = ipc::SharedMemoryInterface<MemCanastos>::get(AGV_SHMEM_CANASTOS_PATH, zonaKey, DSM_ENABLED ? DSMID_CANASTOS_IZQ : 0);
        break;
    case AGV_SHMEM_CANASTOS_KEY_DER:
        shMemCanastos = ipc::SharedMemoryInterface<MemCanastos>::get(AGV_SHMEM_CANASTOS_PATH, zonaKey, DSM_ENABLED ? DSMID_CANASTOS_DER : 0);
        break;
    case AGV_SHMEM_CANASTOS_KEY_MED:
        shMemCanastos = ipc::SharedMemoryInterface<MemCanastos>::get(AGV_SHMEM_CANASTOS_PATH, zonaKey, DSM_ENABLED ? DSMID_CANASTOS_MED : 0);
        break;
    }
}

CommunicationCanastos::~CommunicationCanastos() {
}

void CommunicationCanastos::create(char zonaKey) {
	ipc::SharedMemoryInterface<MemCanastos> memTmp =ipc::SharedMemoryInterface<MemCanastos>::createNonExclusive(AGV_SHMEM_CANASTOS_PATH, zonaKey);
	if (!DSM_ENABLED) {
		inicializar(memTmp);
	}
}

void CommunicationCanastos::destroy(char zonaKey) {
	ipc::SharedMemoryInterface<MemCanastos>::destroy(AGV_SHMEM_CANASTOS_PATH, zonaKey);
}

void CommunicationCanastos::inicializar(ipc::SharedMemoryInterface<MemCanastos> memTmp){
    memTmp.lock();
	MemCanastos canastosMem;
	Canasto vacio;
	vacio.cantidad = 0;
	vacio.idAGV = 0;
	vacio.idPieza = 0;
	vacio.uso = 0;
	for(int i=0; i < MAX_CANASTOS; i++) {
		canastosMem.canastos[i] = vacio;
	}
	canastosMem.canastoDeEspera1 = 0;
	canastosMem.canastoDeEspera2 = 0;
	memTmp.write(canastosMem);
	memTmp.unlock();
}

bool CommunicationCanastos::atenderEsperaDePiezaEnCinta1(TipoPieza pieza) {
	MemCanastos canastosMem = this->shMemCanastos.read();
	bool espera = canastosMem.canastoDeEspera1 == pieza;
	if (espera) {
		canastosMem.canastoDeEspera1 = -1;
		this->shMemCanastos.write(canastosMem);
	}
	return espera;
}

bool CommunicationCanastos::atenderEsperaDePiezaEnCinta2(TipoPieza pieza) {
	MemCanastos canastosMem = this->shMemCanastos.read();
	bool espera = canastosMem.canastoDeEspera2 == pieza;
	if (espera) {
		canastosMem.canastoDeEspera2 = -1;
		this->shMemCanastos.write(canastosMem);
	}
	return espera;
}

void CommunicationCanastos::reemplazarCanasto(Canasto canasto, int pos) {
	MemCanastos canastosMem = this->shMemCanastos.read();
	CLogger::log("Canasto de pieza " + StringUtils::itos(canasto.idPieza) + " con " + StringUtils::itos(canasto.cantidad));
	CLogger::log("A reemplazar en pos " + StringUtils::itos(pos));

	if (pos >= 0 && pos < MAX_CANASTOS) {
		canastosMem.canastos[pos] = canasto;
		CLogger::log("Reemplazo la pieza " + StringUtils::itos(canastosMem.canastos[pos].idPieza));
	}
	this->shMemCanastos.write(canastosMem);
}

std::vector<Canasto> CommunicationCanastos::obtenerCanastos() {
	std::vector<Canasto> canastos;
	MemCanastos canastosMem;
	this->shMemCanastos.lock();
	canastosMem = shMemCanastos.read();
	for(int i=0; i < MAX_CANASTOS; i++) {
		canastos.push_back(canastosMem.canastos[i]);
	}
	return canastos;
}

void CommunicationCanastos::liberarCanastos() {
	this->shMemCanastos.unlock();
}

int CommunicationCanastos::usarCantidad(TipoPieza pieza, int cantidadAUsar) {
	this->shMemCanastos.lock();
	MemCanastos canastosMem = this->shMemCanastos.read();
	int restante = 0;
	CLogger::log("Buscando pieza " + StringUtils::itos(pieza));
	for(int i=0; i < MAX_CANASTOS; i++) {
		if (canastosMem.canastos[i].idPieza == pieza) {
			CLogger::log("Pieza encontrada");
			restante  = canastosMem.canastos[i].cantidad - cantidadAUsar;
			canastosMem.canastos[i].cantidad = (restante < 0)? 0 : restante;
			this->shMemCanastos.write(canastosMem);
			break;
		}
	}
	CLogger::log("restante " + StringUtils::itos(restante));
	this->shMemCanastos.unlock();
	return restante;
}


EstadoCanasto CommunicationCanastos::getEstadoCanasto(TipoPieza pieza) {
	std::vector<Canasto> canastos = this->obtenerCanastos();

	EstadoCanasto estado;
	// Inicializo
	estado.ausente = true;
	estado.estaVacio = true;
	estado.posicion = CANASTO_AUSENTE;
	for(int i = 0; i < MAX_CANASTOS; i++) {
		if (canastos[i].idPieza == pieza) {
			estado.ausente = false;
			estado.estaVacio = canastos[i].cantidad == 0;
			estado.posicion = i;
			break;
		}
	}
	this->liberarCanastos();
	return estado;
}

void CommunicationCanastos::marcarUso(TipoPieza pieza) {
	this->shMemCanastos.lock();
	MemCanastos canastosMem = this->shMemCanastos.read();
	for(int i=0; i < MAX_CANASTOS; i++) {
		if (canastosMem.canastos[i].idPieza == pieza) {
			if(canastosMem.canastos[i].uso < 2) {
				canastosMem.canastos[i].uso++;
			}
			this->shMemCanastos.write(canastosMem);
			break;
		}
	}
	this->shMemCanastos.unlock();
}

void CommunicationCanastos::desmarcarUso(TipoPieza pieza) {
	this->shMemCanastos.lock();
	MemCanastos canastosMem = shMemCanastos.read();
	for(int i=0; i < MAX_CANASTOS; i++) {
		if (canastosMem.canastos[i].idPieza == pieza) {
			if(canastosMem.canastos[i].uso > 0) {
				canastosMem.canastos[i].uso--;
			}
			this->shMemCanastos.write(canastosMem);
			break;
		}
	}
	this->shMemCanastos.unlock();
}

void CommunicationCanastos::agregarEsperaDePieza(TipoPieza pieza) {
	this->shMemCanastos.lock();
	MemCanastos canastosMem = this->shMemCanastos.read();
	if (canastosMem.canastoDeEspera1 <= 0) {
		canastosMem.canastoDeEspera1 = pieza;
	} else if (canastosMem.canastoDeEspera2 >= 0) {
		canastosMem.canastoDeEspera2 = pieza;
	}
	this->shMemCanastos.write(canastosMem);
	this->shMemCanastos.unlock();
}

}
/* namespace middleware */
